//#include "gateway_error.h"
//#include "gateway_packet.h"
#include "gateway_client.h"
#include <boost/regex.hpp>
#include <boost/format.hpp>
#include <boost/lexical_cast.hpp>  
#include <boost/make_shared.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/ini_parser.hpp>
#include <string.h>

#include "../tool/crc16.h"
#include "../tool/encrpty.h"
#include "../tool/cbase64.h"
#include "../pagefile/pagefile.h"
#include "../mqttservice/mqttservice.h"
#include "../tool/md5.h"
#include "../../liblog/Include/liblog.h"
#include "gateway_taskpool.h"
#include <boost/date_time/posix_time/posix_time.hpp>
#include "../mqttservice/mqttservice.h"
#include "gateway_cache.h"
struct _typeText
{
    const unsigned char type;
    const char* meaning;
};

struct _nameText
{
    const char* name;		//属性名
    const char* type;		//属性类型
    const char* desc;		//属性描述
    _typeText typeText[3];
};
static const _nameText g_NameText[] =
{
    {"vstate", "enum", "阀门状态", {{0, "open"}, {1, "close"}, {2, "abnormal"}}},
    {"ovva",   "bool", "关阀电压告警",{{0, "false"}, {1, "true"}, {0xff, ""}}},
    {"pmark",  "bool", "提示标记",{{0, "false"}, {1, "true"}, {0xff, ""}}},
    {"alarm",  "bool", "报警状态",{{0, "false"}, {1, "true"}, {0xff, ""}}},
    {"mstate", "bool", "余量状态",{{0, "false"}, {1, "true"}, {0xff, ""}}},
    {"cct",    "bool", "计数通道二",{{0, "false"}, {1, "true"}, {0xff, ""}}},
    {"cco",    "bool", "计数通道一",{{0, "false"}, {1, "true"}, {0xff, ""}}},

    {"wmstatus",   "bool", "无线模块状态",{{0, "false"}, {1, "true"}, {0xff, ""}}},
    {"smisign",    "bool", "强磁干扰标志",{{0, "false"}, {1, "true"}, {0xff, ""}}},
    {"foffvmark",  "bool", "强制关阀标记",{{0, "false"}, {1, "true"}, {0xff, ""}}},
    {"cfsign",     "bool", "电路故障标志",{{0, "false"}, {1, "true"}, {0xff, ""}}},
    {"fopenvmark", "bool", "强制开阀标记",{{0, "false"}, {1, "true"}, {0xff, ""}}},
    {"ovamark",    "bool", "关阀报警标记",{{0, "false"}, {1, "true"}, {0xff, ""}}},
    {"mmark",      "bool", "余量标记",{{0, "false"}, {1, "true"}, {0xff, ""}}},
    {"omark",      "bool", "透支标记",{{0, "false"}, {1, "true"}, {0xff, ""}}},

    {"sfasign",   "bool", "小流量异常标志",{{0, "false"}, {1, "true"}, {0xff, ""}}},
    {"lfasign",   "bool", "大流量异常标志",{{0, "false"}, {1, "true"}, {0xff, ""}}},
    {"glmark",   "bool", "燃气泄漏标志",{{0, "false"}, {1, "true"}, {0xff, ""}}},
    {"dytbsign",   "bool", "干黄管坏标志",{{0, "false"}, {1, "true"}, {0xff, ""}}},
    {"pvalarm",   "bool", "提示电压报警",{{0, "false"}, {1, "true"}, {0xff, ""}}},
    {"csstatus",   "bool", "插卡开关状态",{{0, "false"}, {1, "true"}, {0xff, ""}}},
    {"getstatus",   "bool", "查询状态",{{0, "false"}, {1, "true"}, {0xff, ""}}},
    //{"ovva",   "bool", "关阀电压告警",{{0, "false"}, {1, "true"}, {0xff, ""}}},

};


gateway_client::gateway_client(gateway_stream_ptr stream_ptr)
 :_is_connected(false)
 ,_stream_ptr(stream_ptr)
 ,_mqtt(NULL) {
}

gateway_client::~gateway_client() {
    if (_mqtt)
        delete _mqtt;
    _mqtt = NULL;
    //printf("%ld New client[%s:%u] ~gateway_client().\n", time(NULL), _host.c_str(), _port);
}

/**** gateway_stream_event ****/
int gateway_client::stream_init() {
	_host = _stream_ptr->get_remote_host();
    _port = _stream_ptr->get_remote_port();
    _addr = _host + std::string(":") +boost::lexical_cast<std::string>(_port);

    get_mqtt_config(_mqttconfig);
    _mqtt = new CMQTTService(this);
	//printf("%ld New client[%s] connected.\n", time(NULL), _addr.c_str());
    _client_ptr.reset(this);
	return 0;
}

int gateway_client::stream_clean() {
	//printf("%ld Client[%s:%u] disconnected.\n", time(NULL), _host.c_str(), _port);
    if (_mqtt)
    {
            _mqtt->Stop();
            delete _mqtt;
            _mqtt = NULL;
    }
    gateway_cache::get_instance()->del_client(_strdevid, _addr);
	_client_ptr.reset();
	return 0;
}

int gateway_client::stream_read(unsigned char* data, unsigned int dataLen) {
    unsigned int used = 0;
    _stream_ptr->set_timeout(60);//超时60s
	int ret = handle_parse_packet(data, dataLen, used);
	if (ret < 0)
	{
		//log
		_stream_ptr->close();
		return -1;
	}
	return std::min(dataLen, used);
}

/**** gateway_task ****/
int gateway_client::on_task(void* param) {
	if (param == NULL)
		return -1;

    event_data *pdata = (event_data*)param;
	std::vector<std::string> vecstrjson = pdata->vecjson;
	delete pdata;

    std::vector<std::string>::iterator it = vecstrjson.begin();
    int ret = 0;
    if (_mqtt == NULL)
        return -1;
	for (; it != vecstrjson.end(); it++)
	{
        ret = _mqtt->pushUpdateData((*it).length(), (const void*)(*it).c_str());
		if (ret)
		{
            //log
            LogError(("%s-mqttpush ret:%d, val:%s\r\n", __PRETTY_FUNCTION__, ret, (*it).c_str()));            
			continue;
		}
    }
    return ret;
}


int gateway_client::handle_parse_packet(unsigned char* buf, unsigned int bufLen, unsigned int &used) {
    if ((!buf) || (bufLen < 2))
        return -1;
    
    if (buf[0] != 0x25 && buf[1] != 0x25)
        return -1;

    used = 0;
    unsigned int total = bufLen;
    std::string strhead = "";
    strhead.push_back(0x25);
    strhead.push_back(0x25); //协议头
    std::string strcmdhead = "";
    strcmdhead.push_back(0x55);
    strcmdhead.push_back(0x66);
    strcmdhead.push_back(0x77);
    strcmdhead.push_back(0x88);
    strcmdhead.push_back(0x99);
    unsigned int pos = 0;
    unsigned short cmdlen = 0;
	crc16 crc;
    std::vector<std::string> vecjson;
    vecjson.clear();

    do{
        std::string protoText((char*)(buf + used), total);
        pos = protoText.find(strhead, pos);
        if (pos == std::string::npos)
            return 0;

        cmdlen = protoText.at(pos + 3);
        cmdlen = (cmdlen << 8) | (unsigned char)protoText.at(pos + 2);
        if (total - pos < cmdlen) //最后一帧长度不够，数据没有接收完
            return 0;

        used = used + pos + cmdlen;
        //数据帧crc验证
        std::string strcmd = protoText.substr(pos, cmdlen);//一个完整的数据帧
        if (!crc.Check_CRC((const unsigned char*)strcmd.c_str(), strcmd.length()))
            continue;//crc验证错误,丢掉该帧

        //获取命令帧
        unsigned int cmdpos = strcmd.find(strcmdhead, 0);
        if (cmdpos == std::string::npos)
        {
            continue; //没有找到有效数据
        }
        const unsigned int framelen = 35;//id(5字节)+有效命令长度
        if (cmdlen - cmdpos - strhead.length() <= framelen)
        {
            continue;//命令有错
        }

		//获取设备id
		_strdevid = get_dev_id(strcmd);

        //完整数据帧base64编码
        unsigned int blen = (strcmd.length() + 2)/3 * 4;
        char *basebuf = new char[blen + 1];
        memset(basebuf, 0, blen + 1);
		CBase64::Encoder((const unsigned char*)strcmd.c_str(),strcmd.length(), basebuf, blen);
		
		std::string strjson = boost::str(boost::format("{\"devid\":\"%s\",\"srcdata\":\"%s\",")%_strdevid % std::string(basebuf, blen) );
		delete []basebuf;
        std::string strdata = strcmd.substr(cmdpos + strcmdhead.length(), framelen);

		get_cmd_json(strdata, strjson);
        vecjson.push_back(strjson);
        
        if (gateway_packet_ack()){//响应ack失败
            break;
        }
        
	}while (total - used > 0);
	
	if (vecjson.size() == 0)
		return -1; //没有数据则直接断开

    return handle_mqtt_event(vecjson);
}

int gateway_client::handle_mqtt_event(std::vector<std::string> vecjson)
{
	//获取mqtt id和key
	if (_mqtt->IsConnect() == false &&  _is_connected == false)//没有连接
	{
		std::string strdeviceid = "";
		std::string strdevicekey = "";
		if (!CPagefile::GetInstance().GetNewDeviceInfo(_strdevid, strdeviceid, strdevicekey))
			return -1;

		MD5 md5(strdeviceid + strdevicekey);
		_mqttconfig.strusrname = strdeviceid;
		_mqttconfig.strmqttid = strdeviceid;
		_mqttconfig.strusrpwd = md5.hexdigest();
        _mqttconfig.strkey = strdevicekey;
        
        //
        LogDebug(("%s:mqttid- %s\r\n",  _strdevid.c_str(), _mqttconfig.strmqttid.c_str()));
       //
       gateway_cache::get_instance()->insert_client(_strdevid, _client_ptr);
		if (_mqtt->Start(_mqttconfig))
			return -1;		

		if (_mqtt->devSubscribe())
		{
			_mqtt->disconnect();
			return -1;		
        };
        
        _is_connected = true;
	}
	event_data *ed = new event_data;
    ed->vecjson.clear();
    ed->vecjson = vecjson;
    gateway_taskpool::get_instance()->schedule(boost::static_pointer_cast<gateway_task>(_client_ptr), (void*)ed);
    return 0;
}

int gateway_client::gateway_packet_ack(){
    
    std::string strcack = boost::str(boost::format("252525001005%s06FFFFA23456789000000021010800FFFF")%_strdevid);
    encrpty en;
    std::string strbyte = "";
    en.strhex_to_strbyte(strcack, strbyte);

    //获取本地时间的格式是YYYYMMDDTHHMMSS
    std::string strTime = boost::posix_time::to_iso_string(boost::posix_time::second_clock::local_time()); 
    strTime.replace(0, 2, std::string(""));
    strTime.replace(6, 1, std::string(""));
    //YYMMDDHHMMSS
    unsigned char tmp = 0;
    for (int i = 0; i < 12;)
    {
        tmp = (boost::lexical_cast<unsigned int>(strTime.substr(i, 2))) & 0xff;
        strbyte.push_back(tmp);
        i +=2;
    }
    crc16 crc;
    unsigned short crcval = crc.CRC_Cal((const unsigned char*)strbyte.c_str(), strbyte.length());
    strbyte.push_back((crcval >> 8)& 0x0f);
    strbyte.push_back(crcval& 0x0f);
    strbyte.push_back(0x23);
    if (_stream_ptr->is_open())
    {
        int ret = _stream_ptr->send((unsigned char*)strbyte.c_str(), strbyte.length());
        if (ret > 0)//发送失败
            return -1;
    }
    return 0;
}

std::string gateway_client::get_dev_id(std::string strcmd)
{
    if (strcmd.length() < 10)
        return "";

    unsigned char tmp = (unsigned char)strcmd.at(5);
    encrpty en;
    std::string strid = "";
    en.strbyte_to_strhex(strcmd.substr(6, tmp), strid);
    return strid;
}

int gateway_client::get_cmd_json(std::string strcmd, std::string &strjson)
{
    unsigned int key = 0x6C;
    key = (key << 8) | 0x52;
    key = (key << 8) | 0x4C;
    key = (key << 8) | 0x43;

    //取命令有效值解密
    unsigned int cmdpos = 0;
    std::string cmdencrptydata = strcmd.substr(cmdpos + 5, 30);//30是出去id后的命令帧长度
    encrpty en;
    std::string dstcmd = "";
    en.strencrpty(cmdencrptydata, dstcmd, key);

    onebyte ob;
    ob.byte = dstcmd.at(3);
    twobyte twb;
    twb.byte = dstcmd.at(4);
    threebyte thb;
    thb.byte = dstcmd.at(5);
    const int typetextnum = 3;
    unsigned char tmp = 0;
    int i = 0;
    int j = 0;
    LogDebug(("%s: %s\r\n", "硬件编码", _strdevid.c_str()));
    for (; j < 8; j++)
    {
        tmp = (ob.byte >> j) & 0x01;
        if (i == 0)
        {
            tmp = (ob.byte & 0x03); //去低两位
            j++;
        }

         strjson += "\"" + std::string(g_NameText[i].name) + "\":";
        for (unsigned char k = 0; k < typetextnum; k++)
        {
            if (g_NameText[i].typeText[k].type == tmp)
            {
                if (strcmp(g_NameText[i].type, "enum") == 0)
                    strjson += "\"" + std::string(g_NameText[i].typeText[k].meaning) + "\"";
                else
                    strjson += std::string(g_NameText[i].typeText[k].meaning);
                
                LogDebug(("%s-%s: %s\r\n", g_NameText[i].name, g_NameText[i].desc,g_NameText[i].typeText[k].meaning));
                break;
            }
        }
        strjson.push_back(',');
        
        i++;
    }

    for (j = 0; j < 8; j++, i++)
    {
        tmp = (twb.byte >> j) & 0x01;
        strjson += "\"" + std::string(g_NameText[i].name) + "\":";
        for (unsigned char k = 0; k < typetextnum; k++)
        {
            if (g_NameText[i].typeText[k].type == tmp)
            {
                strjson += std::string(g_NameText[i].typeText[k].meaning);
                LogDebug(("%s-%s: %s\r\n", g_NameText[i].name, g_NameText[i].desc,g_NameText[i].typeText[k].meaning));
                break;
            }
        }
        strjson.push_back(',');

    }

    for (j = 1; j < 8; j++, i++)
    {
        tmp = (thb.byte >> j) & 0x01;
        strjson += "\"" + std::string(g_NameText[i].name) + "\":";
        for (unsigned char k = 0; k < typetextnum; k++)
        {
            if (g_NameText[i].typeText[k].type == tmp)
            {
                strjson += std::string(g_NameText[i].typeText[k].meaning);
                LogDebug(("%s-%s: %s\r\n", g_NameText[i].name, g_NameText[i].desc,g_NameText[i].typeText[k].meaning));
                break;
            }
        }
        strjson.push_back(',');
    }
    strjson.replace(strjson.length() - 1, 1, "}"); //去掉最后一个‘,’
    return 0;
}


int gateway_client::get_mqtt_config(MQTTCONFIG & mqttconfig)
{
    
	std::string zk_hosts;
	try
	{
		boost::property_tree::ptree reader;
		boost::property_tree::ini_parser::read_ini("collectionsvr.ini", reader);
		mqttconfig.strmqtthost = reader.get<std::string>("mqtt.HOSTS");
        mqttconfig.mqttport = reader.get<int>("mqtt.PORT");
	}
	catch (std::exception& ec)
	{
		mqttconfig.strmqtthost = "127.0.0.1";
		mqttconfig.mqttport = 1883;
		LogError(("%s failed.error:%s.\r\n", __PRETTY_FUNCTION__, ec.what()));
		return -1;
	}
    return 0;
}

/*
boost::shared_ptr<gateway_client> gateway_client::get_ptr()
{
    //return boost::dynamic_pointer_cast<gateway_client> (shared_from_this());
    return shared_from_this();
}
*/


int gateway_client::OnConnect(CMQTTService *mq, std::string strid, int rc)
{
    if (rc != 0)
    {
        //连接失败
		LogError(("%s:%s连接MQTT服务器失败,返回错误码:%d\r\n", __PRETTY_FUNCTION__, strid.c_str(), rc));
        return rc;
    }
    
    LogDebug(("%s 连接mqtt服务器成功\r\n", strid.c_str()));
    //mq->devSubscribe();

    //执行get操作
    //mq->pushGetData();
    return 0;
}
int gateway_client::OnDisconnect(CMQTTService *mq, std::string strid, int rc)
{
	LogDebug(("%s:断开,返回码%d \r\n", strid.c_str(), rc));
    if (!mq)
        return 0;
    //mq->reconnect();
    
    return 0;
}
int gateway_client::OnMessage(CMQTTService *mq, std::string strid, ShadowActions actions, std::string payload)
{
	//if (!_stop)
	//_threadpool.schedule(boost::bind(&CTransaction::DealCommandInfo, this, strid, actions, payload));
    LogDebug(("%s 收到消息%s\r\n", strid.c_str(), payload.c_str()));
    return 0;
}
int gateway_client::OnSubscribe(CMQTTService *mq, std::string strid, int mid, int qos_count, const int *granted_qos)
{
    LogDebug(("%s 订阅topic成功成功\r\n", strid.c_str()));
    return 0;
}

int gateway_client::OnUnsubscribe(CMQTTService *mq, std::string strid, int mid)
{
    return 0;
}

int gateway_client::OnPublish(CMQTTService *mq, std::string strid, int mid)
{
    LogDebug(("%s: 上报成功\r\n", strid.c_str()));
    return 0;
}


void gateway_client::close()
{
    _stream_ptr->close();
}